home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 1 (Walnut Creek)
/
Aminet - June 1993 [Walnut Creek].iso
/
aminet
/
text
/
docs
/
how2cod4.txt
< prev
next >
Wrap
Text File
|
1993-01-06
|
50KB
|
1,575 lines
How to write demos that work (Version 4.3) - 3/1/93
===================================================
(or How to bash the metal and get away with it)
(or the Amiga Demo Coders Reference Manual)
by Comrade J, Share and Enjoy (retired)
Thanks to everyone on the internet for sending their suggestions,
bug reports and comments to me on this article. I'll try and keep
this up to date and posted here frequently. Coming soon, source
code for a small intro using all these techniques that you can
use as the base for whatever you want to do....
Now, is anyone out there going to write a good Amiga 1200 demo,
or am I going to have to do it?
--------------------------------------------------------------------
Most demos I've seen use similar startup code to that I was using back
in 1988. Hey guys, wake up! The Amiga has changed quite a bit since
then.
So. Here are some tips on what to do and what not to do:
1. RTFM.
========
Read the F**king manuals. All of them. Borrow them off friends or from
your local public library if you have to.
Read the "General Amiga Development Guidelines" in the dark grey (2.04)
Hardware Reference Manual and follow them TO THE LETTER.
If it says "Leave this bit cleared" then don't set it!
Don't use self-modifying code. A common bit of code I see is:
... in the setup code
move.l $6c.w,old
... at the end of the interrupt
movem.l (sp)+,a0-a6/d0-d7
dc.w $4ef9 ; jmp instruction
old dc.l 0 ; self modifying!!!!
DONT DO THIS!
This is much better (although it still hits $6c which is not a
good thing - It's much better to use AddIntServer() to call your
interrupts,
... in the setup code
move.l VBRBase(a0)
move.l $6c(a0),old ; see under VBR below....
... at the end of the interrupt
movem.l (sp)+,a0-a6/d0-d7
move.l old,-(sp) ; push old address to stack
rts
... in your data section
old dc.l 0
68020 and above processors with cache enabled often barf at the first
piece of code (the cache still contains the JMP 0 instruction
which isn't then altered), but the second piece works fine on the '040.
2. Proper Copper startup.
=========================
(Please look at the startup example code at the end of this file).
IF you are going to use the copper then this is how you should set it
up. The current workbench view and copper address are stored, the
system frozen, and then the copper enabled. On exit the workbench
view is restored.
This guarantees(*) your demo will run on an AGA (Amiga 1200) machine,
even if set into some weird screenmode before running your code.
Otherwise under AGA, the hardware registers can be in some strange states
before your code runs, beware!
The LoadView(NULL) forces the display to a standard, empty position,
flushing the crap out of the hardware registers: Note. There is
a bug in the V39 OS on Amiga 1200/4000 and the sprite resolution is
*not* reset, you will have to do this manually if you use sprites...
Two WaitTOF() calls are needed after the LoadView to wait for both the
long and short frame copperlists of interlaced displays to finish.
See the bottom of this file for a full, tested, example startup.asm
code, that you can freely use for your own productions.
It has been suggested to me that instead of using the GfxBase gb_ActiView
I should instead use the Intuition ib_ViewLord view. This will work
just as well, but there has been debate as to whether in the future
with retargetable graphics (RTG) this will work in the same way. As the
GfxBase is at a lower level than Intuition, I prefer to access it this
way (but thank's for the suggestion Boerge anyway!). Using gb_ActiView
code should run from non-Workbench environments (for example, being
called from within Amos) too... CJ 1, Chris Green (CBM USA) 0 :-)
* - Nothing is ever guaranteed where Commodore are involved. They
may move the hardware registers into chipram next week :-)
3. Your code won't run from an icon.
====================================
You stick an icon for your new demo (not everyone uses the CLI!) and
it either crashes or doesn't give back all the RAM it uses. Why?
Icon startup needs specific code to reply to the workbench message.
With the excellent Hisoft Devpac assember, all you need to do is add
the line
include "misc/easystart.i"
and it magically works!
For those without Devpac, here is the relevent code:
---------------------------------------------------------
* some startup code to make a Workbench execute look like the CLI
* based loosely on RKM Vol 1 page 4-36
* Include this at the front of your program
* after any other includes
* note that this needs exec/exec_lib.i
IFND EXEC_EXEC_I
include "exec/exec.i"
ENDC
IFND LIBRARIES_DOSEXTENS_I
include "libraries/dosextens.i
ENDC
movem.l d0/a0,-(sp) save initial values
clr.l returnMsg
sub.l a1,a1
move.l 4.w,a6
jsr _LVOFindTask(a6) find us
move.l d0,a4
tst.l pr_CLI(a4)
beq.s fromWorkbench
* we were called from the CLI
movem.l (sp)+,d0/a0 restore regs
bra end_startup and run the user prog
* we were called from the Workbench
fromWorkbench
lea pr_MsgPort(a4),a0
move.l 4.w,a6
jsr _LVOWaitPort(A6) wait for a message
lea pr_MsgPort(a4),a0
jsr _LVOGetMsg(A6) then get it
move.l d0,returnMsg save it for later reply
* do some other stuff here RSN like the command line etc
nop
movem.l (sp)+,d0/a0 restore
end_startup
bsr.s _main call our program
* returns to here with exit code in d0
move.l d0,-(sp) save it
tst.l returnMsg
beq.s exitToDOS if I was a CLI
move.l 4.w,a6
jsr _LVOForbid(a6)
move.l returnMsg(pc),a1
jsr _LVOReplyMsg(a6) ; ***** This line was missing from
; previous articles!!!! **********
jsr _LVOPermit(a6)
exitToDOS
move.l (sp)+,d0 exit code
rts
* startup code variable
returnMsg dc.l 0
* the program starts here
even
_main
---------------------------------------------------------
4. How do I tell if I'm running on an Amiga 1200/4000?
======================================================
Do *NOT* check library revision numbers, V39 OS can and does
run on standard & ECS chipset machines (This Amiga 3000
is currently running V39).
This code will check for AGA
move.w $dff07c,d0
cmp.b #$f8,d0
bne.s .notaga
; Do your funky AGA Stuff in here!
.notaga
5. Use Relocatable Code
=======================
If you write demos that run from a fixed address you should be shot.
NEVER EVER DO THIS. It's stupid and completely unnecessary.
If you require bitplanes to be on a 64Kb boundary then try the
following (in pseudo-code because I'm too lazy to write it in asm
for you):
for c=0 to (top of chip ram) step 65536
if AllocAbs(c,NUMBER_OF_BYTES_YOU_WANT) == TRUE then goto ok:
next c:
print "sorry. No free ram. Close down something and retry demo!"
stop
ok: Run_Outrageous_demo with mem at c
Keep your code in multiple sections. Several small sections are
better than one large section, they will more easilly fit in and run
on a system with fragmented memory.
6. Don't Crunch demos!
======================
Don't ever use Tetrapack or Bytekiller based packers. They are crap.
Many more demos fall over due to being packed with crap packers than
anything else. If you are spreading your demo by electronic means
(which most people do now, the days of the SAE Demodisks are long
gone!) then assemble your code, and use LHARC to archive it, you
will get better compression with LHARC than with most runtime
packers.
If you *have* to pack your demos, then use Powerpacker 4+, Turbo
Imploder or Titanics Cruncher, which I've had no problems with myself.
7. Don't use the K-Seka assembler!
==================================
It's dead and buried. Get a life, get a real assembler. Hisoft Devpac
is probably the best all-round assembler, although I use ArgAsm
which is astonishingly fast. The same goes for hacked versions of
Seka.
8. Don't use the hardware unless you have to!
=============================================
This one is aimed particularly at utility authors. I've seen some
*awfully* written utilities, for example (although I don't want
to single them out as there are plenty of others) the Kefrens
IFF converter.
There is NO REASON why this has to have it's own copperlist. A standard
OS-friendly version opening it's own screen works perfectly (I
still use the original SCA IFF-Converter), and multitasks properly.
If you want to write good utilities, learn C.
9. Beware bogus input falling through to Workbench
==================================================
If you keep multitasking enabled and run your own copperlist remember
that any input (mouse clicks, key presses, etc) fall through to the
workbench. The correct way to get around this is to add an input
server to the IDCMP food chain (see - you *do* have to read the
other manuals!) at a high priority to grab all input events before
workbench/cli can get to them.
Look at the sourcecode for Protracker for an excellent example of
how to do the job properly. Well done Lars!
10. Have fun!
=============
Too many people out there (particularly the American OS-Lamic
Fundamentalists) try to tell us that you should never program at a hardware
level. If you're programming for fun, ignore them! But try and put
a little thought into how your code will work on other machines,
nothing annoys people more than downloading 400Kb of demo and then
finding it blows up on their machines. I'm not naming any names, but
there are quite a few groups who I have no intention of downloading
their demos again because I know it's a waste of download. With
the launch of the Amiga 1200 you cannot just write for 1.3 Amiga
500's any more. Let's go out there and write some shit hot demos!
11. Don't Publish Code you haven't checked!
===========================================
Thanks to Timo Rossi for spotting the stupid bug in my copper
setup routine (using LOFList instead of copinit). Funnily enough
my own setup routine uses the correct copinit code:
Please ignore the original file (howtocode.txt) and use this instead.
12. Copper End
==============
I've remembered where this double copper end comes from:
The ArgAsm assembler has copper macros (CMOVE, CWAIT and CEND)
built in, and the CEND macro deliberately leaves two copper
END instructions, the manual states this is important
for compatibility reasons..
When I get back to the office on Monday I'll look this up...
13. Vector Base Register (68010 and up)
=======================================
The 68010 and above processors have a Vector Base Register (VBR)
that allows the exception vector table to be placed anywhere in
RAM, including fast ram. This gives some speed benefits to systems
with this running, but at a cost.
Anything that accesses the interrupt locations directly, for example:
move.l $6c.w,old
move.l MyWickedInterruptCode,$6c.w
won't work... Unfortunately this includes 99.9% of demos.
Boerg Noest (borgen@stud.cs.uit.no) writes....
> Next your text should mention VBR. It's easy - like this:
> move.l 4.w a6
> moveq #0,d0
> btst.b #AFB_68010,AttnFlags+1(a6)
> beq .done
> movec vbr,d0
>.done
> move.l d0,VBRBase
> rts
>
then you just
> move.l VBRBase,a0
move.l $6c(a0),oldinterrupt
> move.l #myinterrupt,$6c(a0)
>
Ok. I don't know how many people use the VBR to offset their interrupts,
I certainly don't as it breaks too much software on my 3000, and it
only gives a minimal speed increase. The main benefit of the 68010
over the 68000 is the loop cache mode. Common 3 word loops like:
moveq #50,d0
.lp move.b (a0)+,(a1)+ ; one word
dbra d0,.lp ; two words
are recognised as loops and speed up dramatically on 68010.
14 Using the blitter.
=====================
If you are using the blitter in your code and you are leaving the
system intact (as you should) always use the graphics.library
functions OwnBlitter() and DisownBlitter() to take control
of the blitter. Remember to free it for system use, many system
functions (including floppy disk data decoding) use the blitter.
Another big mistake I've seen is with blitter/processor timing.
Assuming that a particular routine will be slow enough that a blitter
wait is not needed is silly. Always check for blitter finished, and
wait if you need to.
Don't assume the blitter will always run at the same speed too. Think
about how your code would run if the processor or blitter were running
at 100 times the current speed. As long as you keep this in mind,
you'll be in a better frame of mind for writing compatible code.
Another big source of blitter problems is using the blitter in interrupts.
Most demos do all processing in the interrupt, with only a
.wt btst #6,$bfe001 ; is left mouse button clicked?
bne.s .wt
loop outside of the interrupt. However, some demos do stuff outside the
interrupt too. Warning. If you use blitter in both your interrupt
and your main code, (or for that matter if you use the blitter via the
copper and also in your main code), you may have big problems....
Take this for example:
lea $dff000,a5
bsr WaitBlitterFinish ; check bits for blitter ready
move.l #-1,BLTAFWM(a5) ; set FWM and LWM in one go
move.l #source,BLTAPT(a5)
move.l #dest,BLTDPT(a5)
move.w #100111110000,BLTCON0(a5)
move.w #0,BLTCON1(a5)
move.w #64*height+width/2,BLTSIZE(a5) ; trigger blitter
There is *nothing* stopping an interrupt, or copper, triggering a
blitter operation between the WaitBlitterFinish call and
your final BLTSIZE blitter trigger. This can lead to total system blowup.
Code that may, by luck, work on standard speed machines may die horribly
on faster processors due to timing differences causing this type of
problem to occurr.
The safest way to avoid this is to keep all your blitter calls together,
use the copper exclusively, or write a blitter-interrupt routine to
do your blits for you.
Always remember to do two blitter-wait-checks... eg:
btst.b #DMAB_BLTDONE-8,DMACONR(a1)
btst.b #DMAB_BLTDONE-8,DMACONR(a1)
The first may not give the correct result on machines with early
(non Fat) Agnus chips (eg Amiga 1000, German A2000). The Hardware
Reference manual explains why, if you're interested.
15 NTSC
=======
As an European myself, I'm naturally biased agains the inferior video
system, but even though the US & Canada have a relatively minor Amiga
community compared with Europe (Sorry, it's true :-) we should still
help them out, even though they've never done a PAL Video Toaster for
us (sob!).
You have two options.
Firstly, you could write your code only to use the first 200 display
lines, and leave a black border at the bottom. This annoys PAL owners,
who rightly expect things to have a full display. It took long enough
for European games writers to work out that PAL displays were better.
You could write code that automatically checked which system it is
running on and ran the correct code accordingly:
(How to check: Note, this is probably not the officialy supported method,
but so many weird things happen with new monitors on AGA machines that
I prefer this method, it's simpler, and works under any Kickstart)
move.l 4.w,a6 ; execbase
cmp.b #50,PowerSupplyFrequency(a6) ; 531(a6)
beq.s .pal
jmp I'm NTSC (or more accurately, I'm running from 60Hz power)
.pal jmp I'm PAL (or I'm running from 50hz power).
If people have already switched modes to PAL, or if they are running
some weird software like the ICD Flicker Free Video Prefs thingy, then
this completely ignores them, but that serves them right for trying
to be clever :-)
Probably better would be to check VBlankFrequency(a6) [530(a6)]
as well, if both are 60Hz then it's definately a NTSC machine. If
one or more are 50Hz, then it's probably a better idea to run in PAL.
Under Kickstart 2.04 or greater, the Display Database can be accessed.
Any program can enquire of the database what type of displays
are available, so for example "I want a 50hz 15Khz PAL screen. Can
I display it on this Amiga?" (Unfortunately it doesn't take
an ASCII string like that, but it's not much more dificult). Of
course many users will have the default monitor installed (PAL or
NTSC) and not realise that they can have extra modes by dragging
the monitor icon into their Monitors drawer, and of course
this doesn't work on Kickstart 1.3 machines.
Now, if you want to force a machine into the other display system
you need some magic pokes: Here you go (beware other bits in
$dff1dc can do nasty things. One bit can reverese the polarity
on the video sync, not to healthy for some monitors I've heard...)
To turn a NTSC system into PAL (50Hz)
move.w #32,$dff1dc ; Magically PAL
To turn a PAL system into NTSC (60Hz)
move.w #0,$dff1dc ; Magically NTSC
Remember: Not all displays can handle both display systems!
Commdore 1084/1084S, Philips 8833/8852 and multisync monitors
will, and very few US TV's will handle PAL signals (especially
if being used with a NTSC Amiga modulator). I gather that
most NTSC machines are Amiga 2000's, so perhaps this isn't
a problem.
So come on you NTSC users, tell us how you would prefer
the demos written!
16 Programming AGA hardware
===========================
I've just got this interesting text file which I thought should be
included with this document. I've now translated it into
better English :-)
"The following information was gathered by Junkie/PMC Fr and Yragael.
Junkie bought a 1200 and started to dissassemble the workbench copperlist.
Thanks to this important work and his impressive speed (which lead me
to dissassemble the copperlist too, I (Yragel) bring you the following
information:
More will follow (unless we get the official AGA hardware reference
manual) [You'll be lucky :-) CJ]
We now wait to see your productions on the 1200, and with your cooperation
we can trip into the hardware of the A1200. [? Are these guys French
or what? :-)]
(next issue: Sprite corrections, HAM8+, other graphic modes, 3 words
copperlists ...)
***************************************************************************
USING THE SUPERHIRES MODE
To use the SuperHires mode (1280 pixels wide), just use the bit 6 of
register $0100
bit 6 | Mode SuperHires
-----------------------
0 | Normal
-----------------------
1 | SuperHires
-----------------------
***************************************************************************
USING 8 BITPLANES
The number of bitplanes available used to be no more than 7 and was coded
using the bits 14 to 12 of register $0100. To use 8 bitplanes, just use
bit 4 of register $0100. The value of bits 14 to 12 will then not be
considered anymore (CJ - It's probably better to set this to %111 for
future compatibility)
bit 4 | 8 bitplanes mode
------------------------
0 | 0 to 7 bitplanes (from bits 12 - 14)
------------------------
1 | 8 bitplanes
------------------------
***************************************************************************
ACCESSING 24 BITS COLOURS
The 24 bit colour values are coded using 2 words:
- the first receives the 4 high bits of each R, G and B componants
- the second receives the 4 low bits of each R, G and B componants
To modify a color using 24 bits coding, you must use 2 coppers-moves on the
same color register. The first move must always be the move of the
word of the 3*4 high bits, the second move is the move of the word of the
3*4 low bits.
You set whether to write the high or the low bits
by setting or clearing bit 9 of register $0106
bit 9 | Components access
-----------------------------------------------------------------
0 | Access to the 4 high bits of components R, G and B
-----------------------------------------------------------------
1 | Access to the 4 low bits of components R, G and B
-----------------------------------------------------------------
** Editorial note: Looks like he got a little confused about
** high and low bits here:
**
** Take $f1f200 (a bright yellow), the high-bits word is $ff0
** (look familiar?), and the low-bits word is $120. - CJ
ex: change $0180 to $00123456 in the copperlist
$01060000
$01800135
$01060200
$01800246
When you want to work using the 12 bits color coding mode, the 3*4 bits
value you move to the color register is considered by the copper as the 3*4
high bits. You don't have to care about $0106. It seems bit 9 of register
$0106 is initialized to 0 at each copjmp.
(Editorial note: The following code *will* work:
$1060000 ; set high bits
$1800123 ; high bits register 0
$1820123 ; high bits register 1
... etc
$1060200 ; set low bits
$1800456 ; low bits register 0
$1820567 ; low bits register 1
... etc
ie, you don't have to do the high bits and low bits of each colour
immediately after each other. This saves lots of needless $106 commands!)
***************************************************************************
ACCESSING THE 256 COLOURS PALETTE
The amiga doesn't work with 256 separate color registers. The same colour
register is used several times to code several colors.
The amiga just works with 8 differents palettes of 32 colors each, using
color registers from $0180 to $01BE.
You can choose the palette you want to access via the bits 11 to 14 of
register $0106
bit 14 | bit 13 | bit 12 | Selected palette
--------------------------------------------------------
0 | 0 | 0 | Palette 0 (color 0 to 31)
--------------------------------------------------------
0 | 0 | 1 | Palette 1 (color 32 to 63)
--------------------------------------------------------
0 | 1 | 0 | Palette 2 (color 64 to 95)
--------------------------------------------------------
0 | 1 | 1 | Palette 3 (color 96 to 125)
--------------------------------------------------------
1 | 0 | 0 | Palette 4 (color 128 to 159)
--------------------------------------------------------
1 | 0 | 1 | Palette 5 (color 160 to 191)
--------------------------------------------------------
1 | 1 | 0 | Palette 6 (color 192 to 223)
--------------------------------------------------------
1 | 1 | 1 | Palette 7 (color 224 to 255)
--------------------------------------------------------
ex: You want to change color 177 to $00123456
Color 177 is color $01A2 of palette 5
$01065000
$01a20135
$01065200
$01a20245
* (Editorial note: This was wrong and has been fixed!!! - CJ)
***************************************************************************
SWITCHING THE PALETTE
You can switch colors. The definition of switching color A and color B is:
- Color registers of colors A and B are NOT modified by the switching
- Color A is displayed using the content of register of color B and
vice-versa
The switching of palette can't be used on just n colors of the palette.
Once you choose a switching value, ALL the palette's colors will be
switched. The switching value is the value separing the colors to be
switched and is coded with bits 15 to 8 of register $010C.
ex: You want all the colors separated by one color in the colorlist to be
switched
$0180 <--
$0182 <--|--
$0184 <-- |
$0186 <-----
$0188 <--------
. |
.
.
Value 2 will be stocked in bits 15 to 8.
The switching works with the palette as if it was a circular palette. I
mean if if the copper consider color 255 and must switch by 1 the colors,
color $0180 will be assiocated to color 255. (??? - CJ)
(Editorial note: A bit confusing here. the high byte of the $dff10c
register (BPLCON4) seems to be an XOR value:
So, if you set the value to $FF, all colour registers are negated,
eg Colour 255 = colour 0, colour 1 = 254, etc...
- CJ)
***************************************************************************
USING SPRITES IN LOWRES, HIRES AND SUPERHIRES
To change the reolution of the sprite, just use bit 7 and 6 of register
$0106
bit 7 | bit 6 | Resolution
--------------------------
0 | 0 | Lowres (140ns)
--------------------------
1 | 0 | Hires (70ns)
--------------------------
0 | 1 | Lowres (140ns)
--------------------------
1 | 1 | SuperHires (35ns)
--------------------------
(Now.. 70ns sprites may not be available unless the Interlace bit in
BPLCON0 is set. Don't ask me why.... CJ)
***************************************************************************
USING 16, 32 AND 64 PIXELS WIDE SPRITES
Well, I still have bug there with sprites in 32 or 64 pixels. Sorry but
the followings informations may have to be corrected.
Use bit 3 and 2 of register $01FC
bit 3 | bit 2 | Wide
-------------------------
0 | 0 | 16 pixels
-------------------------
1 | 0 | 32 pixels
-------------------------
0 | 1 | 32 pixels
-------------------------
1 | 1 | 64 pixels
-------------------------
The copper doesn't read the spritelist in the same way regarding the wide
you choose for your sprite
16 pixels wide reading:
word C1, word C2
word A1, word B1
.
.
.
word An, word Bn
$0000 0000
C1=first control word
C2=second control word
Ai and Bi are combined via OR to form the sprite
32 pixels wide reading:
long C1, long C2
long A1, long B1
.
.
.
long An, long Bn
$0000 0000 0000 00000
C1=first control long
the first control word is the high word of C1. The low word of C1 must
contain the second control word.
C2=second control long
the second control word is the high word of C2. Low word of C2 is $0000
Ai and Bi are combined via OR to form the sprite
64 pixels wide reading:
double C1, double C2
double A1, double B1
.
.
.
double An, double Bn
$0000 0000 0000 00000 0000 0000 0000 00000
C1=first control double
C1=W3:W2:W1:W0 (Wi=words)
W3 is first control word
W2 and W1 are second control word
C2=second control double
C2=W3:W2:W1:W0 (Wi=words)
W3 is second control word
Ai and Bi are combined via OR to form the sprite
***************************************************************************
CHANGING THE SPRITE PALETTE
It is possible to choose the color palette of the sprite. This is done by
the bits 7 and 4 of register $010C.
bit 7 | bit 6 | bit 5 | bit 4 | Starting color of the sprite's palette
-------------------------------------------------------------------------
0 | 0 | 0 | 0 | $0180/palette 0 (coulor 0)
-------------------------------------------------------------------------
0 | 0 | 0 | 1 | $01A0/palette 0 (color 15)
-------------------------------------------------------------------------
0 | 0 | 1 | 0 | $0180/palette 1 (color 31)
-------------------------------------------------------------------------
0 | 0 | 1 | 1 | $01A0/palette 1 (color 47)
-------------------------------------------------------------------------
0 | 1 | 0 | 0 | $0180/palette 2 (color 63)
-------------------------------------------------------------------------
0 | 1 | 0 | 1 | $01A0/palette 2 (color 79)
-------------------------------------------------------------------------
0 | 1 | 1 | 0 | $0180/palette 3 (color 95)
-------------------------------------------------------------------------
0 | 1 | 1 | 1 | $01A0/palette 3 (color 111)
-------------------------------------------------------------------------
1 | 0 | 0 | 0 | $0180/palette 4 (color 127)
-------------------------------------------------------------------------
1 | 0 | 0 | 1 | $01A0/palette 4 (color 143)
-------------------------------------------------------------------------
1 | 0 | 1 | 0 | $0180/palette 5 (color 159)
-------------------------------------------------------------------------
1 | 0 | 1 | 1 | $01A0/palette 5 (color 175)
-------------------------------------------------------------------------
1 | 1 | 0 | 0 | $0180/palette 6 (color 191)
-------------------------------------------------------------------------
1 | 1 | 0 | 1 | $01A0/palette 6 (color 207)
-------------------------------------------------------------------------
1 | 1 | 1 | 0 | $0180/palette 7 (color 223)
-------------------------------------------------------------------------
1 | 1 | 1 | 1 | $01A0/palette 7 (color 239)
-------------------------------------------------------------------------
***************************************************************************
That's all. Thanx you VERY MUCH to Junkie/PMC Fr for his work.
Written by Yragael. Translated & Bugfixed by Comrade J
Chaos. Live it. Learn it. Be it.
_\!/_ The Illuminated Ones _\!/_
/!\ ««««««««««»»»»»»»»»» /!\
Interesting, eh?
17. Keyboard Timings
====================
If you have to read the keyboard by hardware, be very careful
with your timings. Not only do different processor speeds affect
the keyboard timings (for example, in the game F-15 II Strike Eagle
on an Amiga 3000 the key repeat delay is ridiculously slow, you
ttyyppee lliikkee tthhiiss aallll tthhee ttiimmee. You use
up an awful lot of Sidewinders very quickly!), but there are differences
between different makes of keyboard (for example, some Amiga 2000's
come with Cherry keyboards, these have small function keys (same
size as normal alphanumeric keys - these keyboards have different
timings to the normal Mitsumi keyboards.
Again, here's something from Boerge:
>Third, you should warn about f**king up the keyboard read timing. My keyboard
>absolutely does not work with just reading the $bfxxxx turning it to output,
>and writing the reply, and turning it to input again. I do not have any code
>that is especially good, but for now I use this:
> move.b $bfec01,d0 ;get keycode
> not.b d0
> lsr.b #1,d0 ;test up/down flag
> bcs.s .NoStore ;if up, ignore
>
> move.b d0,Key
>.NoStore
>
>;handshake
> bset #6,$bfee01 ;output
> clr.b $bfec01
> moveq #4-1,d0
>.L1 move.b VHPOSR,d1
>.L2 cmp.b VHPOSR,d1
> beq.b .L2
> dbra d0,.L1
>
> bclr #6,$bfee01 ;input again
Remember though, if you have system interrupts and workbench enabled,
keys can fall-through to workbench. For example, press Amiga-Q in
your demo and you may find Workbench closed on return!
18. How to break out of never-ending loops
==========================================
Another great tip for Boerge here:
>This is a simple tip I have. I needed to be able to break out of my
>code if I had neverending loops. I also needed to call my exit code when I did
>this. Therefore I could not just exit from the keyboard interrupt which I have
>taken over(along with the rest of the machine). My solution wa to enter
>supervisor mode before I start my program, and if I set the stack back then
>I can do an RTE in the interrupt and just return from the Supervisor() call.
>This is snap'ed from my code:
>
> lea .SupervisorCode,a5
> move.l sp,a4 ;
> move.l (sp),a3 ;
> EXEC Supervisor
> bra ReturnWithOS
>
>.SupervisorCode
> move.l sp,crashstack ; remember SSP
> move.l USP,a7 ; swap USP and SSP
> move.l a3,-(sp) ; push return address on stack
>
>that last was needed because it was a subroutine that RTSes (boy did I have
>porblems working out my crashes before I fixed that)
>Then I have my exit code:
>
>ReturnWithOS
> tst.l crashstack
> beq .nocrash
> move.l crashstack,sp
> clr.l crashstack
> RTE ; return from supervisor mode
>.nocrash
>
>my exit code goes on after this.
>
>This made it possible to escape from an interrupt without having to care
>for what the exception frames look like.
19. Version numbers!
====================
Put version numbers in your code. This allows the CLI version command
to determine easily the version of both your source and executable
files. Some directory utilities allow version number checking too (so
you can't accidentally copy a newer version of your source over
an older one, for example). Of course, if you pack your files the
version numbers get hidden. Leaving version numbers unpacked
was going to be added to PowerPacker, but I don't know if this is
done yet.
A version number string is in the format
$VER: howtocode4.txt 4.2 02/01/92.
^ ^ ^Version number (date is optional)
| |
| | File Name
|
| Identifier
The Version command searches for $VER and prints the string it finds
following it.
For example, adding the line to the begining of your source file
; $VER: MyFunDemo.s 4.0 01/01/93
and somewhere in your code
dc.b "$VER: MyFunDemo 4.0 01/01/93",0
means if you do VERSION MyFunDemo.s you will get:
MyFunDemo.s 4.0 01/01/93
and if you assemble and do Version MyFunDemo, you'll get
MyFunDemo 4.0 01/01/93
Try doing version howtocode4.txt and see what you get :-)
This can be very useful for those stupid demo compilations
where everything gets renamed to 1, 2, 3, etc...
Just do version 1 to get the full filename (and real date)
Does this work on Kickstart 1.3? I can't remember, I ditched
my 1.3 Kickstart 2 years ago :-)
20. CDTV
========
I've been asked if there is any special advice on how to program
demos to work on CDTV, and if hardware access to the CDTV (for
playing CD Audio, etc) is possible.
The CDTV is essentially a 1Mb chip ram Amiga with a CD-ROM drive.
The major difference (apart from lack of fast ram or $c00000 ram)
is that the CDTV roms can take up anything from 100-200Kb of ram.
Many demos fail on CDTV through lack of memory.
You can hack your CDTV to switch on/off these roms (put a switch
on JP15), when switched off the CDTV has a full 1Mb of memory and
more software works, but you can still play audio CD's in the CD
drive..
I have no information on how to program the CDTV at the hardware
level. Currently the only supported way to access the CDTV
special functions is by the CDTV.DEVICE, a standard ROM device
that can be OpenDevice()d and sent IORequests. I don't think
I'm allowed to give out the documentation for this, sorry :-(
21. Copper Wait Commands
========================
The Hardware Reference manual states a copper wait for the start
of line xx is done with:
$xx01,$fffe
However (as many of you have found out), this actually triggers
just before the end of the previous line (around 4 or 5 low-res
pixels in from the maximum overscan border).
For most operations this is not a problem (and indeed gives a little
extra time to initialise stuff for the next line), but if you are
changing the background colour ($dff180), then there is a noticalbe
'step' at the end of the scanline.
The correct way to do a copper wait to avoid this problem is
$xx07,$fffe.
This just misses the previous scanline, so the background colour is
changed exactly at the start of the scanline, not before.
22. Screen Modulos (thanks Magnus for this one...)
==================================================
Don't assume bitplane modulos (BPL0MOD and BPL1MOD) will be
set to zero. If you require zero modulos set them, at the start
of your copperlist is as good a place as any.
Under V39 OS the workbench is interleaved by default, so the
modulo can be huge...
23. Open Graphics Library! (again, thanks Magnus)
=================================================
I've never seen this in use before, but Magnus spotted
it. It's got to be one of the worst pieces of code I've
ever seen! Don't ever do this!
move.l 4.w,a0 ; get execbase
move.l (a0),a0 ; wandering down the library list...
move.l (a0),a0 ; right. I think this is graphics.library
; now goes ahead and uses a0 as gfxbase...
Oh yes, graphics.library is always going to be second down the chain from
Execbase?
LISTEN and LISTEN good. If you want to access gfxbase (or any other
library base) OPEN the library. Do not wander down the library
chain, either by guesswork or by manually checking for "graphics.library"
in the library base name. OpenLibrary() will do this for you.
24. Protracker Replay code bug
==============================
I've just got the Protracker 2.3 update, and the replay code (both
the VBlank and CIA code) still has the same bug from 1.0!
At the front of the file is an equate
>DMAWait = 300 ; Set this as low as possible without losing low notes.
And then it goes on to use 300 as a hard coded value, never refering
to DMAWait!
Now, until I can get some free time to write a reliable scanline-wait
routine to replace their DBRA loops (does anyone want to write a better
Protracker player? Free fame & publicity :-), I suggest you change
the references to 300 in the code (except in the data tables!) to
DMAWait, and you make the DMAWait value *MUCH* higher.
I use 1024 on this Amiga 3000 without any apparent problem, but
perhaps it's safer to use a value around 2000. Has anyone tried
Protracker on a 68040 machine, if so, what DMAWait value in Prefs
is needed to make all modules sound ok?
25. Optimise mode on produces crap code?
========================================
If you're using Devpac and have found that the OPT o+ flag produces
crap code, then you need to add the option o3-. I can't remember
what this option does, my Devpac 3 manual is at the office.
26. Argasm produces crap code, whatever happens
===============================================
First, Argasm (unlike Devpac) from the Command Line or if called from
Arexx using Cygnus Ed (my prefered system) defaults to writing linkable
code, so you need to add
opt l- (disable linkable code)
If you find that your Argasm executables fail then check you haven't
got any BSR's across sections! Argasm seems to allow this, but of
course the code doesn't work. Jez San from Argonaut software who
publish ArgAsm says it's not a bug, but a feature of the linker...
Yeah right Jez...
But Argasm is *fast*, and it produces the *fastest* non-working
code of any assembler :-)
I still use it though, but Devpac comes in handy for checking
code every now and then. Argonaut have abandoned ArgAsm so
the last version (1.09d) is the last. There will be no more...
27. Help! I'm starting to code in assembler. Where do I begin?
==============================================================
If you are just starting to learn programming, and you want
a good place to begin learning assembler, buy Amos!. It's
very easy to write assembler code, load it into amos and test it.
For example, take this routine:
;simplemaths.s
add.l d0,d1 ; add contents of d0 to d1
rts
Assemble this with Devpac and what do you get? Not a lot.
Now, load AMOS and type this:
Pload "ram:simplemaths",1 ' load executable file into bank 1
Input "Enter a number ";n1
Input "Enter another number ";n2
dreg(0) = n1 ' Store n1 in 68000 register d0
dreg(1) = n2 ' Store n2 in 68000 register d1
call(1) ' Run your machinecode routine
Print n1;" plus ";n2;" equals ";dreg(1) ' returns result in d1
You can start playing with 68000 instructions this way, seeing how
they work, without having to 'jump in the deep end' writing
routines to set up displays, copperlists, windows or writing to
the console. Once you have got the hang of 68000, you can drop
Amos.
28 How can I tell what processor I am running on?
=================================================
Look inside your case. Find the large rectangular (or Square) chip,
read the label :-)
Or...
move.l 4.w,a6
move.w AttnFlags,d0 ; get processor flags
d0.w is then a bit array which contains the following bits
Bit Meaning if set
0 68010 processor fitted
1 68020 processor fitted
2 68030 processor fitted
3 68040 processor fitted
4 68881 MMU fitted
5 68882 MMU fitted
There may well be other flags set now, I only have old documentation
at home..
DO NOT assume that the system has a >68000 if the word is non-zero!
68881 chips are available on add-on boards without any faster processor.
And don't assume that a 68000 processor means a 7Mhz 68000. It may well
be a 14Mhz processor.
So, you can use this to determine whether specific processor functions
are available (more on 68020 commands in a later issue), but *NOT*
to determine values for timing loops. Who knows, Motorola may
release a 100Mhz 68020 next year :-)
29 All addresses are 32 bit
===========================
"Oh look" says clever programmer. "If I access $dcdff180 I can access
the colour0 hardware register, but it confuses people hacking my
code!".
Oh no you can't. On a machine with a 32-bit address bus (any
accelerated Amiga) this doesn't work. And all us hackers know this
trick now anyway :-)
Always pad out 24-bit addresses (eg $123456) with ZEROs in the high
byte ($00123456). Do not use the upper byte for data, for storing
your IQ, for scrolly messages or for anything else.
Similarly, on non ECS machines the bottom 512k of memory was paged
four times on the address bus, eg:
move.l #$12345678,$0
move.l $80000,d0 ; d0 = $12345678
move.l $100000,d1 ; d1 = $12345678
move.l $180000,d2 ; d2 = $12345678
This does not work on ECS and upwards!!!! You will get meaningless
results if you try this, so PLEASE do not do it!
30. New Chipsets?
=================
TO : ALL CODERS IN THE AMIGA DEMO-/GAMESCENE !!!
New Low- Highend Chipset
------------------------
Got this message from a BBS...
>As we heard from serious Commodore developers, there
>will be a new Low-end and a High-end chipset.
This is no secret. This was announced by Lew Egelbrecht (sp?)
head of Commodore Engineering a couple of months back
>The High-end chipset will feature totally new customchips.
>They will bring 16 Bit Sound and some other new features.
>There will be no DSP (Digital Signal Processor) like
>the MOTOROLA 68851 in this AMIGA. Instead of it, there
>will take a new Commodore own Signal Processor part in this
>wonderful machine.
This is not what I heard. I head the AT&T DSP would probably
be used (a true floating point DSP, unlike the integer one
found in the Atari Falcon).
The 68851 is a Memory Management Unit for the 68020, not a DSP.
>The new chips are not fully compatible to AA Chips. Most of
>the new AA Registers like $dff106 and $dff10c will be changed.
>That's the reason, why Commodore didn't released a new
>A1200 and A4000 Hardware Reference Manual.
This is exactly what I have heard from *very* reliable sources.
It may be that AGA chips are a temporary solution inbetween
ECS and the new (AAA?) Superchips...
I wonder if the low-end AAA chipset will be any more AGA
compatible than the high-end?
>The old Registers won't be changed.
>Consequence: If Coders use the old (Normal & ECS) registers,
>that are documented from Commodore, there are no probs with
>the High-end chips. But if they use AA Registers, the new
>AMIGA will propably CRASH.
You have been warned! But what are the chances we get AAA
hardware information. :-(
>Probably publishing date of this AMIGA: Summer '93 (August).
More likely early 1994. CBM won't release any new machines
while AGA machines are still selling well....
>
>Other facts:- The consumer price of the A4000 will turn under
> $1200 in 1993!
Not for the 68040 version. The A4000/030 (Amiga 4000 with
25Mhz 680EC30 chip) may reach $1500 or less.
> - Kickstart 4.0 is finished!
Yeah right :-)
>The truth of this facts is nearly 100 %.
Hmmmmm....
>Text from SMC of ABYSS
>{written on 30.12.92}
Commented by CJ on 2nd Jan 1993
31. Action Replay Cartridges
============================
These things are great fun, even more so if you get into the
'sysop mode' (Allows disassembly of ram areas not previously
allowed by Action Replay, including non-autoconfig ram and
the cartridge rom!)
To get into sysop mode on Action Replay 1 type:
LORD OLAF
To get into sysop mode on Action Replay 2 type:
MAY
THE
FORCE
BE
WITH
YOU
To get into sysop mode on Action Replay 3 type the same as
Action Replay 2. After this you get a message
"Try a new one".
Then type in
NEW
and sysop powers are granted!
Startup Code
============
I've seperated this out now, cut out this file and keep it safe
(you may need a grown up to help you with this :-)
8<-------8<-------8<-------8<-------8<-------8<-------8<-------8<-------
*
* Startup.asm - A working tested version of startup from Howtocode3.txt
*
* CJ - 31/12/92 (Happy new year) [comradej@althera.demon.co.uk]
*
* This code sets up one of two copperlists (one for PAL and one for NTSC)
* machines. It shows something to celebrate 3(?) years since the Berlin
* wall came down :-) Press left mouse button to return to normality.
* Tested on Amiga 3000 (ECS/V39 Kickstart) and Amiga 1200 (AGA/V39)
* Read Howtocode3.txt for information on this source!
*
* $VER: startup.asm V2.0 With added fibre and no artificial preservatives
*
*
opt l-,o+ ; auto link, optimise on
; opt o3- ; add this for Devpac Assembler
section mycode,code ; need not be in chipram
incdir "include:"
include "exec/types.i"
include "exec/funcdef.i" ; keep code simple and
include "exec/exec_lib.i" ; easy to read - use
include "graphics/gfxbase.i" ; the includes!
include "graphics/graphics_lib.i"
include "misc/easystart.i" ; Allows startup from
; icon
StartCopper:
move.l 4.w,a6 ; get ExecBase
lea gfxname,a1 ; graphics name
moveq #0,d0 ; any version
jsr _LVOOpenLibrary(a6)
tst.l d0
beq End ; failed to open? Then quit
move.l d0,gfxbase
move.l d0,a6
move.l gb_ActiView(a6),wbview
; store current view address
; gb_ActiView = 32
move.w #0,a1 ; clears full long-word
jsr _LVOLoadView(a6) ; Flush View to nothing
jsr _LVOWaitTOF(a6) ; Wait once
jsr _LVOWaitTOF(a6) ; Wait again.
move.w $dff07c,d0
cmp.b #$f8,d0
bne.s .notaga
move.w #0,$dff1fc ; reset sprites (fix V39 bug)
.notaga
; Now you can hit the copper!
move.l 4.w,a6
jsr _LVOForbid(a6) ; Suspend multitasking!
cmp.b #50,VBlankFrequency(a6) ; Am I *running* PAL?
bne.s .ntsc
move.l #mycopper,$dff080 ; bang it straight in.
bra.s .lp
.ntsc move.l #mycopperntsc,$dff080
.lp btst #6,$bfe001
bne.s .lp
CloseDown:
move.l 4.w,a6
jsr _LVOPermit(a6) ; Enable multitasking
move.l wbview,a1
move.l gfxbase,a6
jsr _LVOLoadView(a6) ; Fix view
move.l gb_copinit(a6),$dff080 ; Kick it into life
; copinit = 36
move.l a6,a1
move.l 4.w,a6
jsr _LVOCloseLibrary(a6) ; EVERYONE FORGETS THIS!!!!
End: rts ; back to workbench/clc
section mydata,data_c ; keep data & code seperate!
mycopper dc.w $100,$0200 ; otherwise no display!
dc.w $180,$00
dc.w $8107,$fffe ; wait for $8107,$fffe
dc.w $180,$f00 ; background red
dc.w $d607,$fffe ; wait for $d607,$fffe
dc.w $180,$ff0 ; background yellow
dc.w $ffff,$fffe
dc.w $ffff,$fffe
mycopperntsc
dc.w $100,$0200 ; otherwise no display!
dc.w $180,$00
dc.w $6e07,$fffe ; wait for $6e07,$fffe
dc.w $180,$f00 ; background red
dc.w $b007,$fffe ; wait for $b007,$fffe
dc.w $180,$ff0 ; background yellow
dc.w $ffff,$fffe
dc.w $ffff,$fffe
wbview dc.l 0
gfxbase dc.l 0
gfxname dc.b "graphics.library",0
Thanks to everyone who has replied. Any more questions, queries,
or "CJ, you got it wrong again!" type mail to the email
address below....
Thanks to: Vic Ricker, Grue, Timo Rossi, Jesse Michael, John Derek Muir,
Boerge Noest, Christopher Klaus, Doz/Shining, Andrew Patterson, Walter
Dao and Magnus Timmerby.
Wanted! If you can write sections on the following, I'd be very
greatful. Some of these I may do myself eventually..
Good optimisations (eg lea 16(a0),a1 instead of move.l a0,a1 add.l #16,a1)
Simple 68881/882 programming introduction
Bootblocks
Any other short programming tips & tricks
--------------------------------------------------------------------
This text is Copyright (C) 1993 Share and Enjoy, but may be freely
distributed in any electronic form. The copyright of contributions
quoted from other authors remains with the original author. If you would
like to contribute to this file, email me at the address below...
The startup code in this article is freeware and may be used by
anyone for any purpose.
All opinions expressed in this article are my own, and in no way
reflect those of Share and Enjoy or any BBS this file may be found
on.
I didn't write this for fun, I wrote it for you to use! Hopefully
this will grow into a big file that demo coders can use.
If you strongly disagree with anything I write, or you want to send me
some source or demos to test on Amiga 1200/4000 etc, or you have
questions about Amiga programming, or suggestions for future articles,
or just want to chat about the best way to optimise automatic copperlist
generation code, then contact me via email at:
comradej@althera.demon.co.uk, or in alt.sys.amiga.demos
I'm having a few problems with sending email at the moment, so please
be patient if you haven't received a reply. I will try to reply to
every message within a day or two..